<?php

/*
 * Curl类
 */
 
class Curl extends Base {

	//用户代理
	protected $useragent = 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5';
	
	//链接超时时间
	protected $connecttimeout = 30;
	
	//请求超时时间
	protected $timeout = 30;
	
	//是否进行ssl验证
	protected $ssl_verifypeer = FALSE;
	
	//最大重定向次数
	protected $max_redirect = 3;
	
	protected $_valie = array(
		'useragent',
		'connecttimeout',
		'timeout',
		'ssl_verifypeer',
		'max_redirect'
	);
	
	//发送的数据信息
	protected $_datas = array();
	
	//发送的cookie信息
	protected $_cookies = array();
	
	//发送的头信息
	protected $_headers = array();
	
	//返回的头信息
	protected $_headers2 = array();
	
	//最后次调整状态码
	protected $_code = 0;
	
	//http请求信息
	protected $_info = array();
	
	//curl对象
	protected $_curl = NULL;
	
	/**
	 * 初始化
	 * @return boolean 成功返回TRUE，失败返回FALSE
	 */
	public function init()
	{
		if ( ! function_exists('curl_init'))
		{
			$this->set_error('服务器不支持curl');
			return FALSE;
		}
		
		$this->_curl = curl_init();
		
		return TRUE;
	}
	
	/**
	 * get请求
	 * @param string $url 请求地址
	 * @param array $datas 请求附加的数据
	 * @param array $headers 请求头
	 * @param array $cookies 请求附加的cookie
	 * @return 成功返回字符串结果，失败返回FALSE
	 */
	public function get($url, $datas = array(), $headers = array(), $cookies = array())
	{
		return $this->http($url, 'GET', $datas, $headers, $cookies);
	}

	/**
	 * post请求
	 * @param string $url 请求地址
	 * @param array $datas 请求附加的数据
	 * @param array $headers 请求头
	 * @param array $cookies 请求附加的cookie
	 * @return 成功返回字符串结果，失败返回FALSE
	 */
	public function post($url, $datas = array(), $headers = array(), $cookies = array())
	{
		return $this->http($url, 'POST', $datas, $headers, $cookies);
	}
	
	/**
	 * 发送http请求
	 * @param string $url 请求地址
	 * @param string $method 请求方式 get,post
	 * @param array $data 发送的数据
	 * @param array $headers 发送的头信息
	 * @param array $cookies 发送的cookie信息
	 * @return mixed 成功返回字符串结果 失败返回FALSE
	 */
	public function http($url, $method = 'GET', $datas = array(), $headers = array(), $cookies = array())
	{		
		$method = strtoupper($method);
		$this->add_data($datas);
		$this->add_header($headers);
		$this->add_cookie($cookies);
		
		$cookies = array();
		if ($this->_cookies)
		{
			foreach ($this->_cookies as $k => $v)
			{
				$cookies[] = $k.'='.str_replace(';', '', $v);
			}
		}
		$cookies = implode('; ', $cookies);
		
		curl_setopt($this->_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); //使用http1.1
		curl_setopt($this->_curl, CURLOPT_USERAGENT, $this->useragent); //用户代理
		curl_setopt($this->_curl, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout); //链接超时时间
		curl_setopt($this->_curl, CURLOPT_TIMEOUT, $this->timeout); //请求超时时间
		curl_setopt($this->_curl, CURLOPT_RETURNTRANSFER, TRUE); //设置以文件流返回数据，而不是直接输出
		curl_setopt($this->_curl, CURLOPT_ENCODING, ''); //HTTP请求头中"Accept-Encoding: "的值。支持的编码有"identity"，"deflate"和"gzip"。如果为空字符串""，请求头会发送所有支持的编码类型
		curl_setopt($this->_curl, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer); //是否ssl验证
		curl_setopt($this->_curl, CURLOPT_HEADERFUNCTION, array($this, '_headerfunction')); //设置一个回调函数，这个函数有两个参数，第一个是cURL的资源句柄，第二个是输出的header数据。header数据的输出必须依赖这个函数，返回已写入的数据大小。
		curl_setopt($this->_curl, CURLOPT_HEADER, FALSE); //是否返回header请求头信息
		
		switch ($method)
		{
			case 'POST':
				if ($this->_datas)
				{
					curl_setopt($this->_curl, CURLOPT_POST, TRUE); //以POST方式访问
					curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $this->_datas);
				}
				break;
			default:
				$parse = explode('?', $url);
				$arr = array();
				if (isset($parse[1]))
				{
					parse_str($parse[1], $arr);
				}
				$this->_datas = array_merge($arr, $this->_datas);
				$url = $this->_datas ? ($parse[0].'?'.http_build_query($this->_datas)) : $parse[0];
				break;
		}
		
		curl_setopt($this->_curl, CURLOPT_URL, $url);
		curl_setopt($this->_curl, CURLOPT_HTTPHEADER, $this->_headers); //发送header头信息
		curl_setopt($this->_curl, CURLOPT_COOKIE, $cookies); //发送cookie信息
		curl_setopt($this->_curl, CURLINFO_HEADER_OUT, TRUE ); //启用时追踪句柄的请求字符串
		$response = curl_exec($this->_curl);
		$this->_code = curl_getinfo($this->_curl, CURLINFO_HTTP_CODE);
		$this->_info =	curl_getinfo($this->_curl);
		
		if (strpos($this->_code, '3') === 0)
		{
			$i = 1;
			while(strpos($this->_code, '3') === 0)
			{
				curl_setopt($this->_curl, CURLOPT_URL, $this->_info['redirect_url']);
				$response = curl_exec($this->_curl);
				$this->_code = curl_getinfo($this->_curl, CURLINFO_HTTP_CODE);
				$this->_info =	curl_getinfo($this->_curl);
				$i++;
				if ($this->max_redirect > 0 && ($i == $this->max_redirect))
				{
					break;
				}
			}
		}
		$this->_info =	curl_getinfo($this->_curl);
		
		return $response;
	}
	
	/**
	 * 关闭curl句柄
	 * @return void
	 */
	public function close()
	{
		curl_close($this->_curl);
	}
	
	/**
	 * 返回这次请求返回的头信息
	 * @return array 头信息
	 */
	public function get_header()
	{
		return $this->_headers2;
	}
	
	/**
	 * 返回最后次跳转的状态码
	 * @return integer 状态码
	 */
	public function get_code()
	{
		return $this->_code;
	}
	
	/**
	 * 返回这次请求的信息
	 * @return array 信息数组
	 */
	public function get_info()
	{
		return $this->_info;
	}
	
	/**
	 * 添加data数据
	 * @param string $name 名称
	 * @param string $value 值
	 * @return  object 返回$this
	 */
	public function add_data($name, $value = '')
	{
		$this->_add($name, $value, 'data');
		return $this;
	}
	
	/**
	 * 添加cookie数据
	 * @param string $name 名称
	 * @param string $value 值
	 * @return  object 返回$this
	 */
	public function add_cookie($name, $value = '')
	{
		$this->_add($name, $value, 'cookie');
		return $this;
	}

	/**
	 * 添加header数据
	 * @param string $name 名称
	 * @param string $value 值
	 * @return  object 返回$this
	 */
	public function add_header($name, $value = '')
	{
		$this->_add($name, $value, 'header');
		return $this;
	}
	
	/*
	 * 添加数据
	 * @access public
	 * @param	$name string 名称
	 * @param	$value string 值
	 * @param	$type string 数据类型
	 * @return	void
	 */
	/**
	 * 添加数据
	 * @param string $name 名称
	 * @param string $value 值
	 * @param string $type 数据类型
	 * @return  void
	 */
	protected function _add($name, $value, $type)
	{
		$var = '_'.$type.'s';
		
		if(is_array($name))
		{
			foreach($name as $k => $v)
			{
				$this->{$var}[$k] = $v;
			}
		}
		else
		{
			$this->{$var}[$name] = $value;
		}
	}
	
	/**
	 * CURLOPT_HEADERFUNCTION的回调函数
	 * @param resource $ch curl句柄
	 * @param string $header header头信息
	 * @return integer 返回header头长度
	 */
	protected function _headerfunction($ch, $header)
	{
		$i = strpos($header, ':');
		if ( ! empty($i))
		{
			$key = str_replace('-', '_', substr($header, 0, $i));
			$value = trim(substr($header, $i + 2));
			$this->_headers2[$key] = $value;
		}
		return strlen($header);
	}
	
	public function set_useragent($useragent)
	{
		$this->useragent = trim($useragent);
		return $this;
	}
	
	public function set_connecttimeout($connecttimeout)
	{
		$this->connecttimeout = intval($connecttimeout) >= 0 ? intval($connecttimeout) : $this->connecttimeout;
		return $this;
	}
	
	public function set_timeout($timeout)
	{
		$this->timeout = intval($timeout) >= 0 ? intval($timeout) : $this->timeout;
		return $this;
	}
	
	public function set_ssl_verifypeer($ssl_verifypeer)
	{
		$this->ssl_verifypeer = (boolean)$ssl_verifypeer;
		return $this;
	}
	
	public function set_max_redirect()
	{
		$this->max_redirect = intval($max_redirect) >= 0 ? intval($max_redirect) : $this->max_redirect;
		return $this;
	}

}